// Test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <uv.h>
#include <iostream>
#include <ctime>
#include <thread>

void uv_tcp_write_block();
void uv_tcp_write_in_another_thread();
void uv_tcp_stop();
void uv_tcp_recv();
void uv_udp_recv();
void uv_loop();
void uv_loop_stop();

void reg_parent();

int main()
{
	//uv_tcp_write_block();
	//uv_tcp_write_in_another_thread();
	//uv_tcp_stop();
	//uv_tcp_recv();
	//uv_udp_recv();
	//uv_loop();
	uv_loop_stop();

	//reg_parent();

	return 0;
}

// 通不过
void uv_tcp_write_block()
{
	auto loop = uv_default_loop();

	uv_tcp_t tcp;
	uv_tcp_init(loop, &tcp);
	sockaddr_in addr;
	uv_ip4_addr("0.0.0.0", 7835, &addr);
	uv_tcp_bind(&tcp, (const sockaddr*)&addr, 0);

	uv_listen((uv_stream_t*)&tcp, 5, [](uv_stream_t* server, int status) {
		if (status < 0) {
			fprintf(stderr, "New connection error %s\n", uv_strerror(status));
			// error!
			return;
		}

		auto client = new uv_tcp_t;
		uv_tcp_init(server->loop, client);
		uv_accept(server, (uv_stream_t*)client);

		uv_read_start((uv_stream_t*)client, [](uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
			buf->base = new char[64];
			buf->len = 64;
		}, [](uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
			if (nread > 0)
			{
				std::cout.write(buf->base, nread);
				std::cout << std::endl;

				uv_write_t req = { 0 };
				uv_buf_t ubuf;
				ubuf.base = "Hello, world!";
				ubuf.len = std::strlen(ubuf.base);
				uv_write(&req, stream, &ubuf, 1, nullptr);// 运行一下，似乎不行。。
			}
		});
	});

	uv_run(loop, UV_RUN_DEFAULT);

	uv_loop_close(loop);
}

// 没问题
void uv_tcp_write_in_another_thread()
{
	auto loop = uv_default_loop();

	uv_tcp_t tcp;
	uv_tcp_init(loop, &tcp);
	sockaddr_in addr;
	uv_ip4_addr("0.0.0.0", 7835, &addr);
	uv_tcp_bind(&tcp, (const sockaddr*)&addr, 0);

	uv_listen((uv_stream_t*)&tcp, 5, [](uv_stream_t* server, int status) {
		if (status < 0) {
			fprintf(stderr, "New connection error %s\n", uv_strerror(status));
			// error!
			return;
		}

		auto client = new uv_tcp_t;
		uv_tcp_init(server->loop, client);
		uv_accept(server, (uv_stream_t*)client);

		uv_read_start((uv_stream_t*)client, [](uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
			buf->base = new char[64];
			buf->len = 64;
		}, [](uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
			if (nread > 0)
			{
				std::cout.write(buf->base, nread);
				std::cout << std::endl;

				std::thread([](uv_stream_t *stream) {
					auto req = new uv_write_t;
					auto buf = new uv_buf_t;
					buf->base = "Hello, world!";
					buf->len = std::strlen(buf->base);
					req->data = buf;
					uv_write(req, stream, buf, 1, [](uv_write_t* req, int status) {
						std::cout << "success" << std::endl;
						delete req->data;
						delete req;
					});
				}, stream).detach();
			}
		});
	});

	uv_run(loop, UV_RUN_DEFAULT);

	uv_loop_close(loop);
}

// 四种搞法
void uv_tcp_stop()
{
	auto loop = uv_default_loop();

	uv_tcp_t tcp;
	uv_tcp_init(loop, &tcp);
	sockaddr_in addr;
	uv_ip4_addr("0.0.0.0", 7835, &addr);
	uv_tcp_bind(&tcp, (const sockaddr*)&addr, 0);

	uv_listen((uv_stream_t*)&tcp, 5, [](uv_stream_t* server, int status) {
		if (status < 0) {
			fprintf(stderr, "New connection error %s\n", uv_strerror(status));
			// error!
			return;
		}

		auto client = new uv_tcp_t;
		uv_tcp_init(server->loop, client);
		uv_accept(server, (uv_stream_t*)client);

		uv_read_start((uv_stream_t*)client, [](uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
			buf->base = new char[64];
			buf->len = 64;
		}, [](uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
			if (nread > 0)
			{
				std::cout.write(buf->base, nread);
				std::cout << std::endl;
			}
		});
	});

	std::thread([](uv_loop_t *loop) {
		std::this_thread::sleep_for(std::chrono::seconds(10));

		uv_stop(loop);

		/*auto req = new uv_async_t;
		uv_async_init(loop, req, [](uv_async_t* handle) {
			uv_stop(handle->loop);
			delete handle;
		});
		uv_async_send(req);*/
		auto req = new uv_async_t;
		uv_async_init(loop, req, nullptr);
		uv_async_send(req);
	}, loop).detach();

	uv_run(loop, UV_RUN_DEFAULT);

	uv_loop_close(loop);
}

// 没问题
void uv_tcp_recv()
{
	auto loop = uv_default_loop();

	uv_tcp_t tcp;
	uv_tcp_init(loop, &tcp);
	sockaddr_in addr;
	uv_ip4_addr("0.0.0.0", 7835, &addr);
	uv_tcp_bind(&tcp, (const sockaddr*)&addr, 0);

	std::cout << "1:" << std::this_thread::get_id() << std::endl;

	uv_listen((uv_stream_t*)&tcp, 5, [](uv_stream_t* server, int status) {
		if (status < 0) {
			fprintf(stderr, "New connection error %s\n", uv_strerror(status));
			// error!
			return;
		}

		std::cout << "2:" << std::this_thread::get_id() << std::endl;

		std::thread([](uv_stream_t *server) {
			auto client = new uv_tcp_t;
			uv_tcp_init(server->loop, client);
			uv_accept(server, (uv_stream_t*)client);

			std::cout << "3:" << std::this_thread::get_id() << std::endl;

			uv_read_start((uv_stream_t*)client, [](uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
				buf->base = new char[64];
				buf->len = 64;
				std::cout << "4:" << std::this_thread::get_id() << std::endl;
			}, [](uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
				if (nread > 0)
				{
					std::cout.write(buf->base, nread);
					std::cout << std::endl;
				}
				std::cout << "5:" << std::this_thread::get_id() << std::endl;
			});
		}, server).detach();
	});

	uv_run(loop, UV_RUN_DEFAULT);

	uv_loop_close(loop);
}

// 一切正常，可以正常获得 IP
void uv_udp_recv()
{
	auto loop = uv_default_loop();

	uv_udp_t udp;
	uv_udp_init(loop, &udp);
	sockaddr_in addr;
	uv_ip4_addr("127.0.0.1", 7835, &addr);
	uv_udp_bind(&udp, (const sockaddr*)&addr, 0);

	std::cout << "1:" << std::this_thread::get_id() << std::endl;

	uv_udp_recv_start(&udp, [](uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
		buf->base = new char[64];
		buf->len = 64;
		std::cout << "2:" << std::this_thread::get_id() << std::endl;
	}, [](uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags) {
		if (nread > 0)
		{
			auto in = (sockaddr_in*)addr;
			std::cout << inet_ntoa(in->sin_addr) << ":" << in->sin_port << std::endl;

			std::cout.write(buf->base, nread);
			std::cout << std::endl;
		}
		std::cout << "3:" << std::this_thread::get_id() << std::endl;
	});

	uv_run(loop, UV_RUN_DEFAULT);

	uv_loop_close(loop);
}

// 没问题。。。
void uv_loop()
{
	auto loop = uv_default_loop();

	uv_udp_t udp;
	uv_udp_init(loop, &udp);
	sockaddr_in addr;
	uv_ip4_addr("127.0.0.1", 7835, &addr);
	uv_udp_bind(&udp, (const sockaddr*)&addr, 0);

	std::cout << "1:" << std::this_thread::get_id() << std::endl;

	uv_udp_recv_start(&udp, [](uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
		buf->base = new char[64];
		buf->len = 64;
		std::cout << "2:" << std::this_thread::get_id() << std::endl;
	}, [](uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags) {
		if (nread > 0)
		{
			auto in = (sockaddr_in*)addr;
			std::cout << inet_ntoa(in->sin_addr) << ":" << in->sin_port << std::endl;

			std::cout.write(buf->base, nread);
			std::cout << std::endl;
		}
		std::cout << "3:" << std::this_thread::get_id() << std::endl;
	});

	std::thread([](uv_loop_t *loop) {
		std::cout << "4:" << std::this_thread::get_id() << std::endl;

		uv_run(loop, UV_RUN_DEFAULT);

		uv_loop_close(loop);
	}, loop).join();
}

// 不行
void uv_loop_stop()
{
	auto loop = uv_default_loop();

	uv_tcp_t tcp;
	uv_tcp_init(loop, &tcp);
	sockaddr_in addr;
	uv_ip4_addr("0.0.0.0", 7835, &addr);
	uv_tcp_bind(&tcp, (const sockaddr*)&addr, 0);

	std::cout << "1:" << std::this_thread::get_id() << std::endl;

	uv_listen((uv_stream_t*)&tcp, 5, [](uv_stream_t* server, int status) {
		if (status < 0) {
			fprintf(stderr, "New connection error %s\n", uv_strerror(status));
			// error!
			return;
		}

		std::cout << "2:" << std::this_thread::get_id() << std::endl;

		auto client = new uv_tcp_t;
		uv_tcp_init(server->loop, client);
		uv_accept(server, (uv_stream_t*)client);

		server->data = client;

		std::cout << "3:" << std::this_thread::get_id() << std::endl;

		uv_read_start((uv_stream_t*)client, [](uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
			buf->base = new char[64];
			buf->len = 64;
			std::cout << "4:" << std::this_thread::get_id() << std::endl;
		}, [](uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
			if (nread < 0)
			{
				uv_close((uv_handle_t*)stream, NULL);
				return;
			}

			std::cout.write(buf->base, nread);
			std::cout << std::endl;

			delete buf->base;

			std::cout << "5:" << std::this_thread::get_id() << std::endl;
		});
	});

	std::thread([](uv_tcp_t *serv) {
		for (auto i = 0; i < 20; i++)
		{
			uv_sleep(1000);
		}

		auto req = new uv_async_t;
		req->data = serv;
		uv_async_init(serv->loop, req, [](uv_async_t* handle) {

			uv_read_stop((uv_stream_t*)((uv_tcp_t*)handle->data)->data);
			//uv_stop(handle->loop);
		});
		uv_async_send(req);
	}, &tcp).detach();

	uv_run(loop, UV_RUN_DEFAULT);

	uv_loop_close(loop);
}

// 看来不行
void reg_parent()
{
	HKEY hKey;
	DWORD dwDisposition;
	auto ret = RegCreateKeyEx(HKEY_CURRENT_USER, _T("SOFTWARE\\IPCSun\\CanModServ"), 0L, NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition);

	ret = RegOpenKeyEx(hKey, _T(".."), 0, KEY_ALL_ACCESS, &hKey);

	TCHAR tmp[] = _T("123");
	ret = RegSetValue(hKey, _T("test"), REG_SZ, tmp, _tcslen(tmp));

	RegCloseKey(hKey);
}
